#!/usr/bin/env python2

import os
import sys
import socket
import time
import subprocess
import fcntl
import types
import errno
import getopt
import random

from config import Config
from utils import Exp, _dmsg, _dwarn, _derror, _str2dict, _getrack
from movedata import Object, Replica, Node, Location, Rack

class NodePool:
    def __init__(self, storage):
        self.storage = storage
        self.update()

    def update(self):
        self.locations = {}
        self.total = 0
        self.rack_dict = {}
        self.metas = []
        self.deleting = []
        self.admin = None

        retry = 0
        while (retry < 5):
            retry = retry + 1
            nodelist = self.storage.list_node(True)
            if (len(nodelist) == 0):
                time.sleep(1)
                continue
            else:
                break

        for (k, v) in nodelist.items():
            if ('stopped' in v):
                continue

            stat = self.storage.nodeinfo(k)
            if ('admin' in v):
                self.admin = k
                self.metas.append(k)
            elif ('meta' in v):
                self.metas.append(k)

            if ('deleting' in v):
                self.deleting.append(v)
                continue
            elif (stat['writeable'] == "False"):
                continue

            rack = _getrack(k)
            if (self.rack_dict.get(rack) == None):
                self.rack_dict[rack] = Rack(rack)

            self.__add(Node(self.storage, k))
        self.__build()
    
    def __str__(self):
        s = ""
        for (k,v) in self.locations.items():
            s = s + k + ":" + str(v) + ","
        return s

    def __add(self, node):
        size = node.capacity - node.du
        if (self.locations.get(node.name)):
            raise Exp(errno.EEXIST, "%s exist" % (name))

        self.locations[node.name] = size
        self.total = self.total + size

    def __build(self):
        for (k,v) in self.locations.items():
            loc = Location(k, v)
            rack = _getrack(k)
            self.rack_dict[rack].append(loc)

        racks = []
        for (k, v) in self.rack_dict.items():
            racks.append(v)
        self.racks = racks

    def remove(self, name):
        rack = _getrack(name)
        self.rack_dict[rack].pop(name)
        self.locations.pop(name)

    def getlocation(self, _count, skipnode):
        if (_count > len(self.locations)):
            raise Exp(errno.ENOSPC, "no space left")

        _skiprack = {}
        for i in skipnode:
            _skiprack[_getrack(i)] = True

        skiprack = []
        for (k, v) in _skiprack.items():
            skiprack.append(k)

        newrack = []
        for i in self.racks:
            if (i.name in skiprack):
                continue
            else:
                newrack.append(i)
                if (len(newrack) > _count * 2):
                    break

        if (len(newrack) > _count):
            count = _count + 1
        else:
            count = len(newrack)

        a = []
        newnode = []
        i = 0
        while (1):
            if (len(newrack)):
                rack = newrack.pop(random.randrange(0, len(newrack)))
            else:
                rack = self.racks[i % len(self.racks)]

            i = i + 1
            if (i > len(self.locations) * 2):
                raise Exp(errno.ENOSPC, "no space left")

            #print ("rack %s" % (str(rack)))
            loc = rack.pop()
            if (loc.name in skipnode or loc.name in newnode):
                rack.append(loc)
                continue
            a.append(loc)
            newnode.append(loc.name)
            rack.append(loc)

            if (len(a) >= count):
                break

        #reset racks
        self.racks.append(self.racks.pop(0))

        if (len(a) ==  _count + 1):
            a = sorted(a, cmp=lambda x,y:cmp(x.capacity, y.capacity), reverse=True)
            a.pop(-1)

        newa = []
        for i in a:
            newa.append(i.name)

        return newa

    def needmove(self, want, loc):
        rack_dict = {}
        for i in loc:
            rack = _getrack(i)
            rack_dict[rack] = i

        if (want < len(rack_dict)):
            return False

        if (len(rack_dict) >= len(self.racks)):
            return False

        if (len(rack_dict) >= self.storage.config.replica_max / 2):
            return False

        return True
